import React, { createContext, useContext, useImperativeHandle, useState, useEffect, useRef, useLayoutEffect, forwardRef } from 'react';
import gsap from 'gsap';
import { MotionPathPlugin } from 'gsap/MotionPathPlugin.js';
import style from './App.css';

// const style = {
//     width:'100px',
//     height:'100px',
//     lineHeight:'100px',
//     background:'green',
//     color:'#fff',
//     textAlign:'center',
//     marginBottom:'1rem'
// }
// 案例1.通过timeline管理多个组件的动画状态
// function Box({ children, timeline, index }){
//     const el = useRef();
//     useLayoutEffect(()=>{
//         timeline && timeline.to(el.current, { 
//             x:100, 
//             onComplete:()=>console.log('complete'), 
//             onStart:()=>console.log('start'), 
//             onRepeat:()=>console.log('repeat'), 
//             onReverseComplete:()=>console.log('reverse complete') 
//         });
//     },[timeline])
//     return <div style={{...style, backgroundColor:'blue' }} ref={el}>{ children }</div>    
// }

// function Circle({ children, timeline, index, rotation }){
//     const el = useRef();
//     useLayoutEffect(()=>{
//         timeline && timeline.to(el.current, { x:100, rotate:rotation }, 0.5);
//     },[timeline])
//     return <div style={{ ...style, backgroundColor:'green', borderRadius:'50%' }} ref={el}>{ children }</div>
// }

// function App(){
//     const [reversed, setReversed] = useState(false);
//     const [tl, setTl] = useState(null);
//     useLayoutEffect(()=>{ 
//         const ctx = gsap.context(()=>{
//             const tl = gsap.timeline({ defaults:{ duration:4 }, repeat:2, yoyo:true });
//             setTl(tl);
//         })
//         return ()=>ctx.revert();
//     },[])
//     useLayoutEffect(()=>{
//         console.log(tl);
//         tl && tl.reversed(reversed);
//     },[reversed, tl])
//     return (
//         <div>
//             <button onClick={()=>setReversed(!reversed)}>Toggle</button>
//             <Box timeline={tl} index={0}>Box</Box>
//             <Circle timeline={tl} rotation={360} index={1}>Circle</Circle>
//         </div>
//     )
// }

// 案例2.嵌套层级过多时通过createContext传递属性
// const SelectedContext = createContext();
// function Menu(){
//     const { selected, setSelected } = useContext(SelectedContext);
//     const onChange = e=>{
//         setSelected(e.target.value);
//     }
//     return (
//         <div>
//             <label>
//                 <input 
//                     onChange={onChange}
//                     type='radio'
//                     checked={selected === '1' }
//                     value='1'
//                     name='selected'
//                 />
//                 Box1
//             </label>
//             <label>
//                 <input
//                     onChange={onChange} 
//                     type='radio'
//                     checked={selected === '2'}
//                     value='2'
//                     name='selected'
//                 />
//                 Box2
//             </label>
//             <label>
//                 <input 
//                     onChange={onChange}
//                     type='radio'
//                     checked={selected === '3'}
//                     value='3'
//                     name='selected'
//                 />
//                 Box3
//             </label>
//         </div>
//     )   
// }
// function BoxList(){
//     console.log('boxList render...');
//     return (
//         <div>
//             <Box id='1'>Box1</Box>
//             <Box id='2'>Box2</Box>
//             <Box id='3'>Box3</Box>
//         </div>
//     )
// }
// function Box({ children, id }){
//     const el = useRef();
//     const { selected } = useContext(SelectedContext);
//     const ctx = gsap.context(()=>{});

//     useEffect(()=>{
//         return ()=>ctx.revert();
//     },[])
//     useLayoutEffect(()=>{
//         ctx.add(()=>{
//             gsap.to(el.current, {
//                 x:selected === id ? 200 : 0
//             })
//         })
//         console.log(ctx);
//     },[selected])
//     return (
//         <div ref={el} style={{ ...style }}>{ children }</div>
//     )
// }
// function App(){
//     const [selected, setSelected] = useState('2');
//     return (
//         <div>
//             <SelectedContext.Provider value={{ selected, setSelected }}>
//                 <Menu />
//                 <BoxList />
//             </SelectedContext.Provider>
//         </div>
//     )
// }

// 案例3.持续变化时考虑性能不能频繁使用setState,直接引用DOM操作动画
// const Circle = forwardRef((props, ref)=>{
//     const el = useRef();
//     useImperativeHandle(ref, ()=>{
//         return {
//             moveTo(x, y){
//                 gsap.to(el.current, { x, y, delay:props.delay });
//             }
//         }
//     },[])
//     return <div className={style.circle + ' ' + style[props.size]} ref={el}></div>
// })
// function App(){
//     const circleRefs = useRef([]);
//     circleRefs.current = [];
//     const [value, setValue] = useState('');
//     const addCircleRef = ref=>{
//         if ( ref ) {
//             circleRefs.current.push(ref);
//         }
//     }   
//     useEffect(()=>{
//         const { innerWidth, innerHeight } = window;
//         const onMove = ({ clientX, clientY })=>{
//             console.log(clientX, clientY);
//             circleRefs.current.forEach(ref=>{
//                 ref.moveTo(clientX, clientY);
//             })
//         }
//         window.addEventListener('pointermove', onMove);
//         return ()=>{
//             window.removeEventListener('pointermove', onMove);
//         }
//     },[])
//     console.log(circleRefs); 

//     return (
//         <div>
//             <p>Move your mouse around</p>
//             <Circle size='sm' ref={addCircleRef} delay={0} />
//             <Circle size='md' ref={addCircleRef} delay={0.1} />
//             <Circle size='lg' ref={addCircleRef} delay={0.2} />
//         </div>
//     )
// }

// 案例4.创建组件来管理可复用动画
// const FadeIn = forwardRef(({ children, stagger, x }, ref)=>{
//     const el = useRef();
//     const animation = useRef();
//     useLayoutEffect(()=>{
//         const ctx = gsap.context(()=>{
//             animation.current = gsap.from(el.current.children, {
//                 opacity:0,
//                 stagger,
//                 x
//             });
//         })
        
//         return ()=>ctx.revert();
//     },[])
//     useEffect(()=>{
//         if ( typeof ref === 'function' )  {
//             ref(animation.current)
//         } else if ( ref ) {
//             ref.current = animation.current;
//         }
//     },[ref])
//     return <div ref={el}>{ children }</div>
// })
// function App(){
//     const animation = useRef();
//     const handleToggle = ()=>{
//         animation.current.reversed(!animation.current.reversed());
//     }
//     return (
//         <div>
//             <div><button onClick={handleToggle}>toggle</button></div>
//             <FadeIn stagger={1} x={100} ref={animation}>
//                 <div className={style['box']}>Box 1</div>
//                 <div className={style['box']}>Box 2</div>
//             </FadeIn>
//         </div>
//     )
// }

// 案例5.创建从网格中心向外辐射的复杂stagger效果
// var grid = [5, 13];
// var tl = gsap.timeline();

// function animateBoxes(from, axis){
//     tl.to('.' + style.box, {
//         duration:1,
//         scale:0.1,
//         y:60,
//         // yoyo:true,
//         repeat:1,
//         ease:'power1.inOut',
//         stagger:{
//             amount:1.5,
//             grid:grid,
//             // axis取值null, x, y
//             axis,
//             ease:'none',
//             // from取值 center, end, edges, random或者传入index
//             from,
            
//         }
//     })
// }

// function buildGrid(vars){
//     vars = vars || {};
//     let container = document.createElement('div'),
//         rows = vars.grid[0],
//         cols = vars.grid[1],
//         width = vars.width,
//         gutter = vars.gutter,
//         className = vars.className,
//         w = ( width - cols * gutter ) / cols,
//         parent = document.querySelector(vars.parent),
//         css = 'display:inline-block; margin:0 ' + (gutter/width*100) + '%' + (gutter/width*100) + '% 0; width:' + (w/width*100) + '%;',
//         l = rows * cols,
//         box;
//     for(let i = 0; i < l; i++ ) {
//         box = document.createElement('div');
//         box.style.cssText = css;
//         box.setAttribute('class', className);
//         box.index = i;
//         box.setAttribute('data-index', i);
//         if ( vars.onCellClick ) { 
//             box.addEventListener('click', vars.onCellClick);
//         }
//         container.appendChild(box);
//     }
// 	container.style.cssText = "width:" + width + "px; line-height: 0; padding:" + gutter + "px 0 0 " + gutter + "px; display:inline-block;";
//     parent.appendChild(container);
//     return container;
// }
// function App(){
//     useEffect(()=>{
//         buildGrid({ grid, className:style.box, width:1000, gutter:15, parent:'#container' });
//         animateBoxes('center');
//     },[])
//     return (
//         <div>
//             <div id='container' style={{ display:'flex' }}></div>
//             <div className={style['controls']}>
//                 <div className={style['control']}>
//                     <div className={style['control-label']}>from:</div>
//                     <div className={style['control-vertical']}>
//                         <label for='center'><input type='radio' id='center' name='from' value='center' checked /></label>
//                         <label for='end'><input type='radio' id='end' name='from' value='end'/></label>
//                         <label for='edges'><input type='radio' id='edges' name='from' value='edges' /></label>
//                         <label for='random'><input type='radio' id='random' name='from' value='random' /></label>
//                         <label for='center'><input type='radio' id='center' name='from' value='center' /></label>
//                         <label for='index'><input type='radio' id='index' name='from' value='11' /></label>
//                     </div>
//                 </div>
//                 <div className={style['control']}>
//                     <div className={style['control-label']}>axis:</div>
//                     <div className={style['control-vertical']}>
//                         <label for='null'><input type='radio' id='null' name='axis' value='null' checked /></label>
//                         <label for='x'><input type='radio' id='x' name='axis' value='x' /></label>
//                         <label for='y'><input type='radio' id='y' name='axis' value='y' /></label>
//                     </div>
//                 </div>
//             </div>
//         </div>)
// }

// 案例6.通过gsap注册effect来调用动画
// function App(){
//     useEffect(()=>{
//         gsap.registerEffect({
//             name:'fade',
//             defaults:{ duration:2 },
//             effect:(targets, config)=>{
//                 return gsap.to(targets, { duration:config.duration, opacity:0 });
//             }
//         })
//         console.log(gsap.effects.fade('.green'));
//         gsap.delayedCall(3, ()=>gsap.effects.fade('.yellow', { duration:1 }));
//         console.log(gsap);
//     },[])
//     return (
//         <div>
//             <div className={style['box'] + ' ' + 'green'}>Box1</div>
//             <div className={style['box'] + ' ' + 'yellow'}>Box2</div>
//             <div className={style['box'] + ' ' + 'blue'}>Box3</div>
//         </div>
//     )
// }

// 案例7.MotionPath实现路径动画
function App(){
    return (
        <div>
            <svg 
                width="100%" 
                height="100%" 
                // viewBox="-20 0 557 190" 
                id="svg"
            >
            	<circle cx="100" cy="100" r="3" />
            	<circle cx="300" cy="20" r="3" />
            	<path id="path" d="M9,100c0,0,18.53-41.58,49.91-65.11c30-22.5,65.81-24.88,77.39-24.88c33.87,0,57.55,11.71,77.05,28.47c23.09,19.85,40.33,46.79,61.71,69.77c24.09,25.89,53.44,46.75,102.37,46.75c22.23,0,40.62-2.83,55.84-7.43c27.97-8.45,44.21-22.88,54.78-36.7c14.35-18.75,16.43-36.37,16.43-36.37"/>
            	<g id="rect">
            		<rect width="85" height="30" fill="dodgerblue" />
            		<text x="10" y="19" font-size="14">SVG &lt;rect&gt;</text>
            	</g>
            </svg>
            <div id='div'>#div</div>
        </div>
    )
}
export default App;